package cn.sylinx.horm.resource.io;

import cn.sylinx.horm.util.GLog;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * classloader包装
 *
 * @author han
 */
public class ClassLoaderWrapper {

    /**
     * 默认ClassLoader
     */
    ClassLoader defaultClassLoader;

    /**
     * 系统ClassLoader
     */
    ClassLoader systemClassLoader;

    ClassLoaderWrapper() {
        try {
            systemClassLoader = ClassLoader.getSystemClassLoader();
        } catch (SecurityException ignored) {
        }
    }

    /**
     * 获取URL资源
     *
     * @param resource 资源
     * @return URL
     */
    public URL getResourceAsURL(String resource) {
        return getResourceAsURL(resource, getClassLoaders(null));
    }

    public List<URL> getResourceAsURLs(String resource) {
        return getResourceAsURLs(resource, getClassLoaders(null));
    }

    /**
     * 获取URL资源
     *
     * @param resource    资源
     * @param classLoader ClassLoader对象
     * @return URL
     */
    public URL getResourceAsURL(String resource, ClassLoader classLoader) {
        return getResourceAsURL(resource, getClassLoaders(classLoader));
    }

    public List<URL> getResourceAsURLs(String resource, ClassLoader classLoader) {
        return getResourceAsURLs(resource, getClassLoaders(classLoader));
    }

    /**
     * 获取资源输入流
     *
     * @param resource 资源
     * @return InputStream
     */
    public InputStream getResourceAsStream(String resource) {
        return getResourceAsStream(resource, getClassLoaders(null));
    }

    /**
     * 获取资源输入流
     *
     * @param resource    资源
     * @param classLoader ClassLoader对象
     * @return InputStream
     */
    public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
        return getResourceAsStream(resource, getClassLoaders(classLoader));
    }

    /**
     * 加载类
     *
     * @param name 类名称
     * @return Class对象
     * @throws ClassNotFoundException 类找不到异常
     */
    public Class<?> classForName(String name) throws ClassNotFoundException {
        return classForName(name, getClassLoaders(null));
    }

    /**
     * 加载类
     *
     * @param name        类名称
     * @param classLoader 类加载器
     * @return Class对象
     * @throws ClassNotFoundException 类找不到异常
     */
    public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
        return classForName(name, getClassLoaders(classLoader));
    }

    /**
     * 获取资源InputStream
     *
     * @param resource    资源
     * @param classLoader ClassLoader[]对象
     * @return InputStream
     */
    InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
        for (ClassLoader cl : classLoader) {
            if (null != cl) {

                InputStream returnValue = cl.getResourceAsStream(resource);

                if (null == returnValue) {
                    returnValue = cl.getResourceAsStream("/" + resource);
                }

                if (null != returnValue) {
                    return returnValue;
                }
            }
        }
        return null;
    }

    /**
     * 获取URL
     *
     * @param resource    资源
     * @param classLoader 类加载器
     * @return URL
     */
    URL getResourceAsURL(String resource, ClassLoader[] classLoader) {

        URL url;

        for (ClassLoader cl : classLoader) {

            if (null != cl) {

                url = cl.getResource(resource);

                if (null == url) {
                    url = cl.getResource("/" + resource);
                }

                if (null != url) {
                    return url;
                }
            }
        }
        return null;
    }

    /**
     * 获取类路径下所有资源
     *
     * @param resource
     * @param classLoader
     * @return
     */
    List<URL> getResourceAsURLs(String resource, ClassLoader[] classLoader) {

        List<URL> urlList = new ArrayList<>();
        boolean bingo = false;

        try {
            for (ClassLoader cl : classLoader) {
                if (null != cl) {
                    Enumeration<URL> urlEnums = cl.getResources(resource);
                    if (urlEnums != null) {
                        while (urlEnums.hasMoreElements()) {
                            bingo = true;
                            urlList.add(urlEnums.nextElement());
                        }
                    }

                    if (bingo) {
                        return urlList;
                    }
                }
            }
        } catch (IOException e) {
            GLog.error("get resources error", e);
        }

        return urlList;
    }

    /**
     * 加载类
     *
     * @param name        类名称
     * @param classLoader 类加载器
     * @return Class对象
     * @throws ClassNotFoundException 找不到类异常
     */
    Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {

        for (ClassLoader cl : classLoader) {

            if (null != cl) {

                try {
                    return Class.forName(name, true, cl);
                } catch (ClassNotFoundException ignored) {
                    GLog.error("class: {} not found", name);
                }

            }

        }

        throw new ClassNotFoundException("Cannot find class: " + name);

    }

    /**
     * 获取类加载器对象数组
     *
     * @param classLoader 类加载器
     * @return ClassLoader[]对象
     */
    ClassLoader[] getClassLoaders(ClassLoader classLoader) {
        return new ClassLoader[]{classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
                getClass().getClassLoader(), systemClassLoader};
    }

}
